/* 
 * Copyright (c) 2011-, Agilord Kft. - All Rights Reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.agilord.dragonflyp4.module;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.agilord.dragonflyp4.Configuration;
import com.agilord.dragonflyp4.ExifUtils;
import com.agilord.dragonflyp4.ImageFile;
import com.agilord.dragonflyp4.ProcessModule;
import com.agilord.dragonflyp4.TextUtils;

/**
 * The rename module does what the name implies: renames the photo file, using
 * the specified pattern, including title and location information.
 * 
 * @author Istvan Soos
 * @since 1.0
 */
public class RenameModule implements ProcessModule {

	protected NamePart[] parts;

	public RenameModule() {
		super();

		List<NamePart> list = new ArrayList<NamePart>();
		for (String p : Configuration.get().parseCommas("rename.parts")) {
			String[] x = p.split("\\:", 2);
			String id = x[0];
			String[] params = (x.length == 2) ? x[1].split("\\:") : null;

			if ("file".equalsIgnoreCase(id)) {
				list.add(new FileNamePart(params));
			} else if ("title".equalsIgnoreCase(id)) {
				list.add(new TitleNamePart(params));
			} else if ("location".equalsIgnoreCase(id)) {
				list.add(new LocationNamePart(params));
			} else if ("rating".equalsIgnoreCase(id)) {
				list.add(new RatingNamePart(params));
			} else if ("keyword".equalsIgnoreCase(id)) {
				list.add(new KeywordNamePart(params));
			} else {
				throw new RuntimeException("Unknow rename part: " + p);
			}
		}
		this.parts = list.toArray(new NamePart[list.size()]);
	}

	public void process(ImageFile image) {
		StringBuilder name = new StringBuilder();
		for (NamePart np : this.parts) {
			String v = np.getValue(image);
			if (v != null) {
				v = v.trim();
				if (v.length() > 0) {
					if (name.length() > 0)
						name.append("-");
					name.append(v);
				}
			}
		}

		if (name.length() == 0)
			return;

		String ext = "";
		int li = image.getFile().getName().lastIndexOf('.');
		if (li >= 0)
			ext = image.getFile().getName().substring(li).toLowerCase();

		String targetName = TextUtils.filenameCompatible(name.toString()) + ext;

		if (targetName.equals(image.getFile().getName()))
			return;

		// setting original filename
		String source = ExifUtils.getStringValue(image.getExif(), "Source");
		if (source == null) {
			source = image.getFile().getName();
			// setting
			ProcessBuilder pb = new ProcessBuilder(
			        Configuration.get().getExiftool(),
			        "-overwrite_original_in_place",
			        "-Source=" + source,
			        image.getFile().getAbsolutePath());
			try {
				pb.start().waitFor();
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
			image.getExif().put("Source", source);
		}

		// renaming file
		File targetFile = new File(image.getFile().getAbsoluteFile().getParentFile(), targetName);
		image.getFile().renameTo(targetFile);
		image.setFile(targetFile);
	}

	public void reportSummary() {
	}

	public static abstract class NamePart {
		protected NamePart(String[] params) {
			super();
		}

		public abstract String getValue(ImageFile image);
	}

	public static class FileNamePart extends NamePart {

		protected String prefix = "";
		protected String postfix = "";

		protected FileNamePart(String[] params) {
			super(params);
			if (params != null) {
				if (params.length > 0 && params[0] != null)
					prefix = params[0].trim();
				if (params.length > 1 && params[1] != null)
					postfix = params[1].trim();
			}
		}

		public String getValue(ImageFile image) {
			String name = ExifUtils.getStringValue(image.getExif(), "Source");
			if (name == null)
				name = image.getFile().getName();

			name = TextUtils.removeAccents(name);

			// remove extension
			int li = name.lastIndexOf('.');
			if (li >= 0)
				name = name.substring(0, li);

			// spaces to dashes
			name = name.replaceAll("\\s+", "-");
			return prefix + name + postfix;
		}

	}

	public static class TitleNamePart extends NamePart {

		protected int length = 50;

		protected TitleNamePart(String[] params) {
			super(params);
			if (params != null) {
				if (params.length > 0 && params[0] != null) {
					try {
						length = Integer.parseInt(params[0]);
					} catch (Exception ex) {
					}
				}
			}
		}

		public String getValue(ImageFile image) {
			String name = ExifUtils.getTitle(image.getExif());
			if (name == null)
				name = ExifUtils.getDescription(image.getExif());
			if (name == null)
				return null;

			// process
			name = TextUtils.removeAccents(name);
			name = name.toLowerCase();
			name = name.trim().replaceAll("\\s+", "-");

			if (length > 0 && name.length() > length) {
				int x = name.lastIndexOf("-", length);
				if (x >= length / 2)
					name = name.substring(0, x);
			}

			return name;
		}

	}

	public static class LocationNamePart extends NamePart {

		protected int length = 50;

		protected LocationNamePart(String[] params) {
			super(params);
			if (params != null) {
				if (params.length > 0 && params[0] != null) {
					try {
						length = Integer.parseInt(params[0]);
					} catch (Exception ex) {
					}
				}
			}
		}

		public String getValue(ImageFile image) {
			String location = ExifUtils.getLocation(image.getExif());
			if (location == null)
				return null;

			// process
			location = TextUtils.removeAccents(location);
			location = location.toLowerCase();
			location = location.trim().replaceAll("\\s+", "-");

			if (length > 0 && location.length() > length) {
				int x = location.lastIndexOf("-", length);
				if (x >= length / 2)
					location = location.substring(0, x);
			}

			return location;
		}

	}

	public static class RatingNamePart extends NamePart {

		protected String prefix = "";
		protected String postfix = "";
		protected String missing = null;

		protected RatingNamePart(String[] params) {
			super(params);
			if (params != null) {
				if (params.length > 0 && params[0] != null)
					prefix = params[0].trim();
				if (params.length > 1 && params[1] != null)
					postfix = params[1].trim();
				if (params.length > 2 && params[2] != null)
					missing = params[2].trim();
			}
		}

		public String getValue(ImageFile image) {
			Long rv = ExifUtils.getLongValue(image.getExif(), "Rating");
			if (rv == null)
				return missing;
			return prefix + rv + postfix;
		}

	}

	public static class KeywordNamePart extends NamePart {

		protected String name;
		protected String exists;
		protected String missing;

		protected KeywordNamePart(String[] params) {
			super(params);
			name = params[0].trim();
			if (params.length > 1 && params[1] != null)
				exists = params[1].trim().toLowerCase();
			if (params.length > 2 && params[2] != null)
				missing = params[2].trim().toLowerCase();
			if (exists != null && exists.length() == 0)
				exists = null;
			if (missing != null && missing.length() == 0)
				missing = null;
			if (exists == null && missing == null)
				exists = name.toLowerCase();
			if (exists != null)
				exists = exists.replaceAll("\\s+|_", "-");
			if (missing != null)
				missing = missing.replaceAll("\\s+|_", "-");
		}

		public String getValue(ImageFile image) {
			List<String> list = ExifUtils.getStringList(image.getExif(), "Keywords");
			if (list == null)
				return null;
			if (list.contains(name))
				return exists;
			return missing;
		}
	}
}
